#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/epoll.h>

#include "somb.h"
#include "somb_sock.h"
#include "somb_common.h"
#include "somb_log.h"

#define SOMB_SOCK_MAX_EPOLL_EVENT   10
static int epoll_fd = -1;
int32_t somb_sock_init(void)
{
    epoll_fd = epoll_create(1); //size must be greater than 0
    if(epoll_fd < 0)
    {
        SOMB_LOG_ERR("somb sock:pid(%d) create epoll fd failed",getpid());
        return SOMB_FAIL;
    }

    return SOMB_OK;
}

int32_t somb_sock_poll_add(int fd)
{
    int ret;
    struct epoll_event e_event;
    e_event.data.fd = fd;     
    e_event.events = EPOLLIN;
	ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &e_event);
	if(ret < 0)
	{
        SOMB_LOG_ERR("somb sock:pid(%d) add(%d) to epoll fd failed",getpid(),fd);
        return SOMB_FAIL;
	}

    return SOMB_OK;
}
int32_t somb_sock_poll_delete(int fd)
{
    int ret;
	ret = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
	if(ret < 0)
	{
        SOMB_LOG_ERR("somb sock:pid(%d) delete (%d) to epoll fd failed",getpid(),fd);
        return SOMB_FAIL;
	}

    return SOMB_OK;
}

int somb_sock_poll(int fds[],uint32_t fdsize)
{
    int ret = 0;
    struct epoll_event wait_event[SOMB_SOCK_MAX_EPOLL_EVENT];  
    ret = epoll_wait(epoll_fd,wait_event,SOMB_SOCK_MAX_EPOLL_EVENT,-1);
    if(ret < 0)
    {
        SOMB_LOG_ERR("somb sock:pid(%d) epoll_wait return %d failed,%s",getpid(),ret,strerror(errno));
        return -1;
    }
    else if(ret == 0)
    {
        SOMB_LOG_ERR("somb sock:pid(%d) epoll_wait timeout,%s",getpid(),strerror(errno));
        return -2;
    }

    uint8_t loop=0;
    for(;(loop<ret)&&(loop<fdsize);loop++)
    {
        if((wait_event[loop].events & EPOLLIN) == EPOLLIN)
        {
            fds[loop] = wait_event[loop].data.fd;
        }
    }

   return 0; 
}
int32_t somb_sock_send(int skfd,char *DestAddr,void *buffer,uint32_t buffer_size,bool MoreBuffer)
{
    int32_t ret = SOMB_OK;
#if 0 
    if((NULL == DestAddr)||(NULL == buffer))
    {
        SOMB_LOG_ERR("somb sock:pid(%d) send to Dest SubNs(%s),parameter wrong ",getpid(),DestAddr);
        return -1;
    }

    int flags = (MoreBuffer)?MSG_MORE:0;

    struct sockaddr_un addr_un;
    memset(&addr_un,0,sizeof(struct sockaddr_un));

    addr_un.sun_family = AF_UNIX;
    snprintf(addr_un.sun_path,sizeof(addr_un.sun_path),"%s",DestAddr);
    ret  = sendto(skfd,buffer,buffer_size,flags,(struct sockaddr *)&addr_un,SUN_LEN(&addr_un));
    if(-1 == ret)
    {
        SOMB_LOG_ERR("somb sock:pid(%d) send to Dest SubNs(%s) return(%d) failed,errno=%s",getpid(),DestAddr,ret,strerror(errno));
        ret = SOMB_FAIL;
    }
    else
    {
        SOMB_LOG_DEBUG("somb sock:pid(%d) send to Dest SubNs(%s) return(%d) ",getpid(),DestAddr,ret);
        ret =  SOMB_OK;
    }
#else
    ret  = send(skfd,buffer,buffer_size,0);
    if(-1 == ret)
    {
        SOMB_LOG_ERR("somb sock:pid(%d) send to Dest SubNs(%s) return(%d) failed,errno=%s",getpid(),DestAddr,ret,strerror(errno));
        ret = SOMB_FAIL;
    }
    else
    {
        SOMB_LOG_DEBUG("somb sock:pid(%d) send to Dest SubNs(%s) return(%d) ",getpid(),DestAddr,ret);
        ret =  SOMB_OK;
    }
    
#endif

    return ret;
}

int32_t somb_sock_recv(int skfd,char *SrcAddr,uint32_t SrcAddrSize,void*buffer,uint32_t buffer_size)
{

    if((NULL == SrcAddr)||(NULL == buffer))
    {
        SOMB_LOG_ERR("somb sock:pid(%d) recv failed,parameter wrong ",getpid());
        return -1;
    }

    struct sockaddr_un addr_un;
    memset(&addr_un,0,sizeof(struct sockaddr_un));
    socklen_t socklen=sizeof(struct sockaddr_un);
    int32_t len = recvfrom(skfd,buffer,buffer_size,0,(struct sockaddr *)&addr_un,&socklen);

    snprintf(SrcAddr,SrcAddrSize,"%s",addr_un.sun_path);

    return len;
}

